home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_10_01
/
1001038a
< prev
next >
Wrap
Text File
|
1991-10-03
|
6KB
|
288 lines
/*
* Get input string, with VMS-style input line editing
* and previous-command scrolling.
*
* Written for Turbo C 2.0 / Borland C++ 2.0
* Bob Bybee, 2/91
*/
#include <stdio.h>
#include <string.h>
/* ASCII key definitions */
#define ESC_KEY 0x1b
#define DELETE_KEY 0x7f
#define BACKSPACE_KEY 0x08
#define RETURN_KEY 0x0d
#define CTRL(x) ((x) & 0x1f)
/* Arbitrary values for tracking cursor key entry.
* These happen to match PC BIOS scan codes, but any
* unique values would work.
*/
#define UP_ARROW 0x4800
#define DOWN_ARROW 0x5000
#define RIGHT_ARROW 0x4d00
#define LEFT_ARROW 0x4b00
/* MAX_RECALL is two greater than the number of lines
* we want in the "lastlines" recall buffer.
*/
#define MAX_RECALL 22
#define RECSUB(x) (((x) + MAX_RECALL) % MAX_RECALL)
#define RECALL_LEN 100
static char lastlines[MAX_RECALL][RECALL_LEN];
static int num_got; /* # chars in input buffer */
static int cursor_pos; /* cursor position on line */
static int lastptr = 0; /* ptr to last line entered */
static char erase_one[] = "\b \b"; /* erase one character */
static char *str_ptr; /* ptr to current input string */
/* prototypes for this file */
static void clear_line( void );
static int cursor_right( void );
static int cursor_left( void );
static int get_char_esc( void );
static void put_str( char *str );
/* external functions (see listing2.c) */
void sys_putchar( char ch );
int sys_getchar( void );
/*
* get_str() is called by main() to get a line of input.
* The input line is placed in "str" and will be no
* more than "len" characters.
*/
void get_str( char *str, int len )
{
int i, c, curptr, insert_mode = 1;
num_got = 0;
cursor_pos = 0;
str_ptr = str; /* copy the buffer pointer */
curptr = RECSUB(lastptr + 1);
lastlines[curptr][0] = '\0';
lastlines[RECSUB(curptr + 1)][0] = '\0';
if (len > RECALL_LEN - 1) /* limit len to RECALL_LEN */
len = RECALL_LEN - 1;
while (1)
{
c = get_char_esc();
if (c == RETURN_KEY)
break;
else if (c == DELETE_KEY || c == BACKSPACE_KEY)
{
if (cursor_left())
{
++cursor_pos;
for (i = cursor_pos; i < num_got; ++i)
{
str[i - 1] = str[i];
sys_putchar(str[i]);
}
sys_putchar(' ');
for (i = cursor_pos; i <= num_got; ++i)
sys_putchar('\b');
--num_got;
--cursor_pos;
}
}
else if (c == CTRL('X')) /* erase line? */
clear_line();
else if (c == CTRL('A')) /* insert/overtype? */
insert_mode ^= 1;
else if (c == CTRL('B')) /* beginning-of-line? */
{
while (cursor_left())
;
}
else if (c == CTRL('E')) /* end-of-line? */
{
while (cursor_right())
;
}
else if (c == CTRL('R')) /* recall last line? */
{
clear_line();
strcpy(str, lastlines[lastptr]);
if ((num_got = strlen(str)) > 0)
{
put_str(str);
break;
}
}
else if (c == UP_ARROW)
{
clear_line();
if (lastlines[curptr][0] != '\0' ||
lastlines[RECSUB(curptr - 1)][0] != '\0')
{
curptr = RECSUB(curptr - 1);
strcpy(str, lastlines[curptr]);
put_str(str);
cursor_pos = num_got = strlen(str);
}
}
else if (c == DOWN_ARROW)
{
clear_line();
if (lastlines[curptr][0] != '\0' ||
lastlines[RECSUB(curptr + 1)][0] != '\0')
{
curptr = RECSUB(curptr + 1);
strcpy(str, lastlines[curptr]);
put_str(str);
cursor_pos = num_got = strlen(str);
}
}
else if (c == LEFT_ARROW)
{
if (cursor_pos > 0)
{
sys_putchar('\b');
--cursor_pos;
}
}
else if (c == RIGHT_ARROW)
cursor_right();
else if (' ' <= c && c < 0x7f && num_got < len - 1)
{
if (insert_mode)
{
/* Move right, all the characters
* to the right of cursor_pos.
*/
for (i = num_got; i > cursor_pos; --i)
str[i] = str[i - 1];
str[cursor_pos] = c;
for (i = cursor_pos; i <= num_got; ++i)
sys_putchar(str[i]);
for (i = cursor_pos; i < num_got; ++i)
sys_putchar('\b');
++num_got;
++cursor_pos;
}
else /* insert is off, use overtype mode */
{
str[cursor_pos] = c;
sys_putchar(c);
if (cursor_pos == num_got)
++num_got;
++cursor_pos;
}
}
}
str[num_got] = '\0';
sys_putchar('\n');
/* If this line is non-empty, and different
* from the last one accepted, store it into
* the recall buffer.
*/
if (num_got > 0 && strcmp(str, lastlines[lastptr]) != 0)
{
lastptr = RECSUB(lastptr + 1);
strcpy(lastlines[lastptr], str);
}
}
/*
* Move the cursor right one position, by echoing the
* character it's currently over.
* Return 1-OK, 0-can't move.
*/
static int cursor_right( void )
{
if (cursor_pos < num_got)
{
sys_putchar(str_ptr[cursor_pos]);
++cursor_pos;
return (1);
}
return (0);
}
/*
* Move the cursor left one position, by echoing
* a backspace. Return 1-OK, 0-can't move.
*/
static int cursor_left( void )
{
if (cursor_pos > 0)
{
sys_putchar('\b');
--cursor_pos;
return (1);
}
return (0);
}
/*
* Erase all characters on the current line.
*/
static void clear_line( void )
{
while (cursor_right())
; /* move right, to end of line */
cursor_pos = 0;
while (num_got > 0)
{
put_str(erase_one); /* then, erase to left */
--num_got;
}
}
/*
* Get a character, with escape processing.
* Handles special sequences like "ESC [ A" for up-arrow.
* This function would need to be modified to handle
* keyboards that are neither PC's nor VT-100's.
*/
static int get_char_esc( void )
{
int ch;
ch = sys_getchar();
if (ch != ESC_KEY)
return (ch);
ch = sys_getchar();
if (ch != '[')
return (ch);
ch = sys_getchar();
if (ch == 'A')
return (UP_ARROW); /* was ESC [ A */
else if (ch == 'B')
return (DOWN_ARROW); /* was ESC [ B */
else if (ch == 'C')
return (RIGHT_ARROW); /* was ESC [ C */
else if (ch == 'D')
return (LEFT_ARROW); /* was ESC [ D */
else
return (ch);
}
/*
* Put a string to sys_putchar().
*/
static void put_str( char *str )
{
while (*str != '\0')
sys_putchar(*str++);
}